#ifndef __MY_UTIL_HPP__
#define __MY_UTIL_HPP__

#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include <memory>
#include <jsoncpp/json/json.h>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <cmath>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include "bundle.h"

namespace cloud
{
    /*文件操作集合类*/
    class FileUtil
    {
    public:
        FileUtil(const std::string filename) : _filename(filename) {}

        /*删除文件*/
        bool Remove()
        {
            if (Exists() == false)
            {
                printf("file not exists\n");
                return false;
            }

            int n = remove(_filename.c_str());
            return n == 0;
        }

        /*获取文件大小*/
        int64_t FileSize()
        {
            struct stat st;
            bzero(&st, sizeof(st));
            if (stat(_filename.c_str(), &st) < 0)
            {
                printf("get file size failed\n");
                return -1;
            }

            return st.st_size;
        }

        /*获取文件最后一次修改时间*/
        time_t LastMTime()
        {
            struct stat st;
            bzero(&st, sizeof(st));
            if (stat(_filename.c_str(), &st) < 0)
            {
                printf("get file modify time failed\n");
                return -1;
            }

            return st.st_mtim.tv_sec;
        }

        /*获取文件最后一次访问时间*/
        time_t LastATime()
        {
            struct stat st;
            bzero(&st, sizeof(st));
            if (stat(_filename.c_str(), &st) < 0)
            {
                printf("get file access time failed\n");
                return -1;
            }

            return st.st_atim.tv_sec;
        }

        /*获取文件名*/
        std::string FileName() 
        { 
            size_t pos=_filename.find_last_of("/");
            if(pos==std::string::npos) return _filename;
            return _filename.substr(pos+1);
        }

        /*从指定位置获取指定长度的文件内容*/
        bool GetPosLen(std::string *body, size_t pos, size_t len)
        {
            if(pos+len>FileSize())
            {
                printf("len too much\n");
                return false;
            }

            std::ifstream ifs(_filename,std::ios::binary);
            if(ifs.is_open()==false)
            {
                printf("get content,open file failed\n");
                return false;
            }

            ifs.seekg(pos,std::ios::beg);
            body->resize(len);
            ifs.read(&(*body)[0],len);
            if(ifs.good()==false)
            {
                printf("read file failed\n");
                ifs.close();
                return false;
            }

            ifs.close();
            return true;
        }

        /*获取整个文件内容*/
        bool GetContent(std::string *body)
        {
            return GetPosLen(body,0,FileSize());
        }

        /*向文件内写入指定内容*/
        bool SetContent(const std::string &body)
        {
            std::ofstream ofs(_filename,std::ios::binary);
            if(ofs.is_open()==false)
            {
                printf("set content,open file failed\n");
                return false;
            }

            ofs.write(body.c_str(),body.size());
            if(ofs.good()==false)
            {
                printf("write file failed\n");
                ofs.close();
                return false;
            }

            ofs.close();
            return true;
        }

        /*压缩文件存放到指定文件中*/
        bool Compress(const std::string &packname)
        {
            //1.获取需要压缩文件的内容
            std::string body;
            if(GetContent(&body)==false)
            {
                printf("compress,get content failed\n");
                return false;
            }

            //2.压缩指定内容，获得压缩后的内容
            std::string pack_content=bundle::pack(bundle::LZIP,body);

            //3.将压缩内容写入到指定文件中
            FileUtil fu(packname);
            if(fu.SetContent(pack_content)==false)
            {
                printf("compress,set content failed\n");
                return false;
            }
            
            return true;
        }

        /*解压缩文件存放到指定文件中*/
        bool UnCompress(const std::string &filename)
        {
            //1.获取压缩文件内容
            std::string pack_content;
            if(GetContent(&pack_content)==false)
            {
                printf("uncompress,get content failed\n");
                return false;
            }

            //2.解压缩指定内容
            std::string body=bundle::unpack(pack_content);

            //3.将解压缩后的内容写入到指定文件中
            FileUtil fu(filename);
            if(fu.SetContent(body)==false)
            {
                printf("uncompress,set content failed\n");
                return false;
            }
            
            return true;
        }

        /*判断文件是否存在*/
        bool Exists()
        {
            struct stat st;
            bzero(&st,sizeof(st));
            if(stat(_filename.c_str(),&st)<0) return false;
            return true;
        }

        /*创建目录*/
        bool CreateDirectory()
        {
            if(Exists()==true) return true;
            if(mkdir(_filename.c_str(),0777)<false)
            {
                printf("create directory failed\n");
                return false;
            }
            return true;
        }

        /*遍历目录下的文件*/
        bool ScanDirectory(std::vector<std::string> *arry)
        {
            //1.打开目录
            DIR* dirp=opendir(_filename.c_str());
            if(dirp==nullptr)
            {
                printf("open dir failed\n");
                return false;
            }

            //2.遍历目录下文件
            struct dirent* dt=nullptr;
            while((dt=readdir(dirp))!=nullptr)
            {
                if(dt->d_type==DT_REG)
                {
                    std::string file_path=_filename;
                    file_path+=dt->d_name;
                    arry->push_back(file_path);//存放的就是文件名的路径，而不只是文件名了
                }
            }

            //3.关闭目录
            closedir(dirp);
            return true;
        }

    private:
        std::string _filename;
    };

    /*Json操作集合类*/
    class JsonUtil
    {
    public:
        /*组织json格式数据的序列化*/
        static bool Serialize(const Json::Value &root, std::string *str)
        {
            Json::StreamWriterBuilder swb;
            std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
            std::stringstream ss;
            if(sw->write(root,&ss)!=0)
            {
                printf("json write failed\n");
                return false;
            }
            *str=ss.str();
            return true;
        }

        /*组织json格式数据的反序列化*/
        static bool UnSerialize(const std::string &str, Json::Value *root)
        {
            Json::CharReaderBuilder crb;
            std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
            std::string json_err;
            if(cr->parse(str.c_str(),str.c_str()+str.size(),root,&json_err)==false)
            {
                printf("json read failed:%s\n",json_err.c_str());
                return false;
            }
            return true;
        }
    };

    /*将时间戳转化为指定格式的时间*/
    std::string TimetoStr(time_t t)
    {
        struct tm* tm=localtime(&t);
        char buffer[128];
        bzero(buffer,sizeof(buffer));
        strftime(buffer,sizeof(buffer)-1,"%Y-%m-%d_%H:%M:%S",tm);
        return buffer;
    }

    std::string FsizetoStr(size_t size)
    {
        if(size<1024)
        {
            std::string str=std::to_string(size);
            str+="B";
            return str;
        }
        else if(size<1024*1024)
        {
            double tmp=size;
            size=(size_t)ceil(tmp/1024);
            std::string str=std::to_string(size);
            str+="K";
            return str;
        }
        else if(size<1024*1024*1024)
        {
            double tmp=size;
            tmp=ceil(tmp/1024/1024*10)/10.0;
            char buffer[32];
            bzero(buffer,sizeof(buffer));
            sprintf(buffer,"%.1lf",tmp);
            std::string str=buffer;
            str+="M";
            return str;
        }
        else
        {
            double tmp=size;
            tmp=ceil(tmp/1024/1024/1024*10)/10.0;
            char buffer[32];
            bzero(buffer,sizeof(buffer));
            sprintf(buffer,"%.1lf",tmp);
            std::string str=buffer;
            str+="G";
            return str;
        }
    }
}

#endif